package com.hmy.contract.service.contract.create.feign;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hmy.ccp.common.result.FeignResult;
import com.hmy.contract.bo.request.oss.OssFileUploadRequest;
import com.hmy.contract.bo.response.oss.OssFileUploadResponse;
import com.hmy.contract.common.utils.OssFilePathUtil;
import com.hmy.contract.commons.enums.ContractBusinessTypeEnum;
import com.hmy.contract.commons.enums.ContractStatusEnum;
import com.hmy.contract.dal.mapper.ContractMapper;
import com.hmy.contract.dal.po.ContractPo;
import com.hmy.contract.manager.exit.ExitFormFeignClientManager;
import com.hmy.contract.manager.signature.SignatureFeignClientManager;
import com.hmy.contract.service.contract.IContractService;
import com.hmy.contract.service.contract.create.IContractCreateService;
import com.hmy.contract.service.dto.contract.ContractRevokeDto;
import com.hmy.contract.service.dto.contract.FieldDto;
import com.hmy.contract.service.dto.contract.SignTaskDto;
import com.hmy.contract.service.oss.IOssService;
import com.hmy.contract.service.rdto.ContractActorDetailRdto;
import com.hmy.contract.service.rdto.ContractRdto;
import com.hmy.contract.service.rdto.CreateContractRdto;
import com.hmy.fulfillment.api.bo.request.ExitFormBindContractUrlRequest;
import com.hmy.fulfillment.api.bo.request.ExitFormContractSignedSuccessRequest;
import com.hmy.infrastructure.api.bo.request.signature.*;
import com.hmy.infrastructure.api.bo.response.signature.CreateContractApiResponse;
import com.hmy.infrastructure.api.bo.response.signature.GetSignFileUrlApiResponse;
import com.hmy.infrastructure.api.bo.response.signature.GetSignTaskUrlApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author seven.qi 齐胜南
 * @version 1.0
 * @description
 * @date 2023/12/23 16:12
 */
@Service
@Slf4j
public class ExitElectronicContractCreateService implements IContractCreateService {

    @Resource
    private SignatureFeignClientManager signatureFeignClientManager;

    @Resource
    private ExitFormFeignClientManager exitFormFeignClientManager;

    @Resource
    private ContractMapper contractMapper;

    @Resource
    private IContractService contractService;

    @Resource
    private IOssService ossService;

    @Override
    public String create(CreateContractRdto createContractDto) {
        CreateContractApiRequest createContractApiRequest = convertToRequest(createContractDto);
        CreateContractApiResponse createContractApiResponse = signatureFeignClientManager.createContract(createContractApiRequest);
        return createContractApiResponse.getSignTaskId();
    }

    private CreateContractApiRequest convertToRequest(CreateContractRdto dto) {
        CreateContractApiRequest createContractApiRequest = new CreateContractApiRequest();
        createContractApiRequest.setSignTemplateId(dto.getSignTemplateId());
        createContractApiRequest.setBusinessScene(ContractBusinessTypeEnum.getDescByType(dto.getBusinessType()));
        createContractApiRequest.setTaskSubject(dto.getTaskSubject());
        createContractApiRequest.setActorDetailList(buildActorDetailList(dto));
        createContractApiRequest.setBusinessId(dto.getBusinessId());
        createContractApiRequest.setTransReferenceId(String.valueOf(dto.getBusinessType()));
        return createContractApiRequest;
    }

    private List<ActorDetailApiRequest> buildActorDetailList(CreateContractRdto dto) {
        List<ContractActorDetailRdto> contractActorList = dto.getContractActorDetailList();
        List<ActorDetailApiRequest> list = new ArrayList<>();
        contractActorList.forEach(actor -> {
            ActorDetailApiRequest request = BeanUtil.copyProperties(actor, ActorDetailApiRequest.class);
            list.add(request);
        });
        return list;
    }

    @Override
    public List<FieldDto> fillFieldValue(CreateContractRdto createContractDto) {
        List<FieldDto> fieldList = new ArrayList<>();
        Map<String, Object> fieldMap = createContractDto.getFieldMap();
        for (String key : fieldMap.keySet()) {
            fieldList.add(FieldDto.builder().key(key).value(fieldMap.get(key).toString()).build());
        }
        return fieldList;
    }

    @Override
    public String start(String signTaskId, List<FieldDto> fieldDtoList, CreateContractRdto dto) {

        List<FieldApi> fieldApiList = BeanUtil.copyToList(fieldDtoList, FieldApi.class);

        SignTemplateFieldFillApiRequest signTemplateFieldFillApiRequest = new SignTemplateFieldFillApiRequest();
        signTemplateFieldFillApiRequest.setFieldList(fieldApiList);
        signTemplateFieldFillApiRequest.setSignTemplateId(dto.getSignTemplateId());
        signTemplateFieldFillApiRequest.setSignTaskId(signTaskId);
        signatureFeignClientManager.signTemplateFieldFill(signTemplateFieldFillApiRequest);


        StartSignatureProcessApiRequest startSignatureProcessApiRequest = new StartSignatureProcessApiRequest();
        startSignatureProcessApiRequest.setSignTaskId(signTaskId);
        signatureFeignClientManager.start(startSignatureProcessApiRequest);


        GetSignTaskUrlApiRequest getSignTaskUrlApiRequest = new GetSignTaskUrlApiRequest();
        getSignTaskUrlApiRequest.setSignTaskId(signTaskId);
        getSignTaskUrlApiRequest.setActorId(dto.getContractActorDetailList().get(0).getActorId());
        FeignResult<GetSignTaskUrlApiResponse> signTaskUrl = signatureFeignClientManager.getSignTaskUrl(getSignTaskUrlApiRequest);

        return signTaskUrl.getData().getSignTaskUrl();
    }

    @Override
    public void beforeCreate(CreateContractRdto dto) {

    }

    @Override
    public void afterCreate(CreateContractRdto dto) {
        ContractRdto contractRdto = dto.getContractRdto();
        ContractPo contractPo = new ContractPo();
        contractPo.setStatus(ContractStatusEnum.WAITING_SIGN.getStatus());
        contractPo.setContractTaskId(contractRdto.getContractTaskId());
        SignTaskDto signTaskDto = new SignTaskDto();
        signTaskDto.setContractSignTaskUrl(dto.getUrl());
        contractPo.setContractSignTaskUrl(JSONUtil.toJsonStr(signTaskDto));
        LambdaQueryWrapper<ContractPo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ContractPo::getContractId, contractRdto.getContractId());
        wrapper.eq(ContractPo::getIsDeleted, Boolean.FALSE);
        contractMapper.update(contractPo, wrapper);

        ExitFormBindContractUrlRequest exitFormBindContractUrlRequest = new ExitFormBindContractUrlRequest();
        exitFormBindContractUrlRequest.setContractId(dto.getContractRdto().getContractId());
        exitFormBindContractUrlRequest.setContractSignUrl(dto.getUrl());
        exitFormFeignClientManager.bindExitFormContractSignUrl(exitFormBindContractUrlRequest);
    }

    @Override
    public Long notify(ContractRevokeDto dto) {
        Long contractId = contractService.contractInfoBySignTaskId(dto.getSignTaskId());
        ContractPo contractRo = contractService.getById(contractId);

        String path = "";

        try {
            path = saveSignedFile(contractRo);
        } catch (Exception e) {
            log.error("save signed file exception", e);
        }

        if (StrUtil.isNotEmpty(path)) {
            try {
                path = saveSignedFileToOss(path, contractRo.getContractNo());
            } catch (Exception e) {
                log.error("save signed file to oss exception", e);
            }
        }
        try {
            notifyStatus(contractRo);
        } catch (Throwable throwable) {
            log.error("notify contract status failed", throwable);
        }
        LambdaQueryWrapper<ContractPo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ContractPo::getContractId, contractRo.getContractId());
        wrapper.eq(ContractPo::getIsDeleted, Boolean.FALSE);
        ContractPo contractPo = new ContractPo();
        contractPo.setStatus(ContractStatusEnum.SIGNED.getStatus());
        contractPo.setContractSignFileUrl(path);
        contractPo.setSignTime(LocalDateTime.now());
        contractPo.setUpdaterName("system");
        contractPo.setUpdateTime(LocalDateTime.now());
        contractService.update(contractPo, wrapper);
        return contractId;
    }

    private String saveSignedFileToOss(String path, String contractNo) {
        String storePath = OssFilePathUtil.createElectronicContractPath(contractNo);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        HttpUtil.download(path, outputStream, true);
        OssFileUploadRequest ossFileUploadRequest = new OssFileUploadRequest();
        ossFileUploadRequest.setInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
        ossFileUploadRequest.setStorePath(storePath);
        OssFileUploadResponse ossFileUploadResponse = ossService.ossFileUploadByStream(ossFileUploadRequest);
        return ossFileUploadResponse.getOssPrefix();
    }

    private String saveSignedFile(ContractPo contractPo) {
        GetSignFileUrlApiRequest getSignFileUrlApiRequest = new GetSignFileUrlApiRequest();
        getSignFileUrlApiRequest.setSignTaskId(contractPo.getContractTaskId());
        FeignResult<GetSignFileUrlApiResponse> signFileUrl = signatureFeignClientManager.getSignFileUrl(getSignFileUrlApiRequest);
        return signFileUrl.getData().getSignFileUrl();
    }

    private void notifyStatus(ContractPo contractPo) {
        ExitFormContractSignedSuccessRequest exitFormContractSignedSuccessRequest = new ExitFormContractSignedSuccessRequest();
        exitFormContractSignedSuccessRequest.setContractId(contractPo.getContractId());
        exitFormFeignClientManager.contractSignedSuccess(exitFormContractSignedSuccessRequest);
    }
}
